package com.pafcio.sudoku;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class Board {

	private Area[] areas = new Area[9];
	
	public Board(Area[][] areas) {
		this.areas[0] = areas[0][0]; 
		this.areas[1] = areas[0][1]; 
		this.areas[2] = areas[0][2]; 
		this.areas[3] = areas[1][0]; 
		this.areas[4] = areas[1][1]; 
		this.areas[5] = areas[1][2]; 
		this.areas[6] = areas[2][0]; 
		this.areas[7] = areas[2][1]; 
		this.areas[8] = areas[2][2];
	}

	public Board(Board inputBoard) {		
		for (int i=0; i<inputBoard.areas.length; i++) {
			Area area = inputBoard.areas[i];
			Area copy = new Area(new Integer[][]{
					area.getRow(0),
					area.getRow(1),
					area.getRow(2)
			});
			
			areas[i] = copy;
		}
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		
		for (int i = 0; i < 9; i++) {
			sb.append(getRow(i)).append("\n");
		}
		sb.delete(sb.length()-1, sb.length());
		return sb.toString();		
	}

	public boolean isOK() {		
		for(Vector row : getRows()){
			if(!row.isOK())
				return false;
		}
		
		for(Vector column: getColumns()){
			if(!column.isOK())
				return false;
		}
		
		return true;
	}

	private Set<Vector> getColumns() {
		Set<Vector> columns = new HashSet<Vector>();
		
		for(int i=0; i<9; i++){
			columns.add(getColumn(i));
		}
		
		return columns;	
	}

	private Set<Vector> getRows() {
		Set<Vector> rows = new HashSet<Vector>();
		
		for(int i=0; i<9; i++){
			rows.add(getRow(i));
		}
		
		return rows;
	}

	public Vector getRow(int rowNumber) {		
		Area[] areasForRow = getAreasForRow(rowNumber);
		int rowInArea = rowNumber % 3;
		
		Integer[] row = new Integer[9];
		System.arraycopy(areasForRow[0].getRow(rowInArea), 0, row, 0, 3);
		System.arraycopy(areasForRow[1].getRow(rowInArea), 0, row, 3, 3);
		System.arraycopy(areasForRow[2].getRow(rowInArea), 0, row, 6, 3);
		
		Vector result = new Vector(row);
		
		return result;		
	}
	
	private Area[] getAreasForRow(int rowNumber) {
		int from = 3 * (rowNumber / 3);
		int to = from + 3;
		return Arrays.copyOfRange(areas, from, to);
	}

	public Vector getColumn(int columnNumber) {
		Area[] areasForRow = getAreasForColumn(columnNumber);
		int columnInArea = columnNumber % 3;
		
		Integer[] column = new Integer[9];
		System.arraycopy(areasForRow[0].getColumn(columnInArea), 0, column, 0, 3);
		System.arraycopy(areasForRow[1].getColumn(columnInArea), 0, column, 3, 3);
		System.arraycopy(areasForRow[2].getColumn(columnInArea), 0, column, 6, 3);
		
		Vector result = new Vector(column);
		
		return result;
	}
	
	private Area[] getAreasForColumn(int columnNumber) {
		Area[] areasForColumn = new Area[]{
				areas[0 + (columnNumber/3)],
				areas[3 + (columnNumber/3)],
				areas[6 + (columnNumber/3)]
		};
		
		return areasForColumn;
	}

	public Integer getValueAt(int row, int col) {
		return getRow(row).getValueAt(col);		
	}

	public void setValueAt(int row, int col, Integer value) {			
		Area area = getAreaFor(row, col);		
		area.setValueAt(row % 3, col % 3, value);
	}

	public Area getAreaFor(int row, int col) {
		int rowX = row / 3;
		int colX = col / 3;
		
		int index = 3 * rowX + colX;
		
		Area area = areas[index];
		return area;
	}
}
